﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Windows.Threading;


namespace Chaos.network
{
    public class udpconnection : connection
    {    
        private UdpClient m_udpclient;
        private bool m_running = false;

        public UdpClient UdpClient
        {
            get { return m_udpclient; }
        }

        public udpconnection(UdpClient in_udpclient, IPEndPoint in_IPEndPoint)
        {
            m_ipendpoint = in_IPEndPoint;
            m_udpclient = in_udpclient;
        }

        public override void start()
        {
            if (!m_running)
            {
                m_running = true;     
                m_thread = new Thread(new ThreadStart(threadmain));
                m_thread.Name = "udpconnection";
                m_thread.Priority = ThreadPriority.BelowNormal;
                m_thread.Start();
                base.start();
            }
        }

        public override void abort()
        {
            if (m_running)
            {
                m_running = false;
                m_udpclient.Close();
                m_udpclient = null;
                //m_thread.Abort();
                m_thread.Join();
                base.abort();
            }
        }
        
        void threadmain()
        {
            Dictionary<String, messagebuffer> messagebuffers = new Dictionary<String, messagebuffer>();      
            
            while (m_running)
            {
                IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Any, 0);
                
                try
                {                
                    if (m_udpclient.Available > 0)
                    {
                        byte[] buffer = m_udpclient.Receive(ref ipendpoint);
                        String key = ipendpoint.ToString();
                        if ( !messagebuffers.ContainsKey(key) )
                        {
                            messagebuffer newmsgbuffer = new messagebuffer();
                            newmsgbuffer.Buffer = new byte[4];
                            newmsgbuffer.ToRead = 4;
                            newmsgbuffer.Read = 0;
                            newmsgbuffer.State = connection.estate.kState_ReadHeader;
                            messagebuffers.Add(key, newmsgbuffer);
                        }

                        messagebuffer msgbuffer = messagebuffers[key];
                        int bufferoffset = 0;
                        int remaining = 0;
                        do
                        {
                            int bufferlength = buffer.Length - bufferoffset;
                            int copycount = Math.Min(bufferlength, msgbuffer.ToRead);
                            remaining = bufferlength - copycount;

                            Array.Copy(buffer, bufferoffset, msgbuffer.Buffer, msgbuffer.Read, copycount);

                            msgbuffer.ToRead -= copycount;
                            msgbuffer.Read += copycount;
                            bufferoffset += copycount;

                            if (msgbuffer.ToRead <= 0)
                            {
                                if (msgbuffer.State == estate.kState_ReadHeader)
                                {
                                    msgbuffer.ToRead = BitConverter.ToInt32(msgbuffer.Buffer, 0) - 4;
                                    msgbuffer.Read = 0;
                                    msgbuffer.Buffer = new byte[msgbuffer.ToRead];
                                    msgbuffer.State = estate.kState_ReadPacket;
                                    
                                }
                                else
                                {
                                    recievedata(ipendpoint, msgbuffer.Buffer, msgbuffer.Buffer.Length);
                                    msgbuffer.Buffer = new byte[4];
                                    msgbuffer.ToRead = 4;
                                    msgbuffer.Read = 0;                                    
                                    msgbuffer.State = estate.kState_ReadHeader;
                                }
                            }
                                                        

                        } while (remaining > 0);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());
                }
            }
            m_udpclient = null;
        }

        public override void senddata(IPEndPoint in_ipendpoint, byte[] buffer, int bufflen)
        {
            try
            {
                m_udpclient.Send(buffer, bufflen, in_ipendpoint);                
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }




    }
}
